export default class MaterialShaderManager{
    // public static basicShaderStr: string;
    private static partitionHeader = 'void main()';
    private static partitionVertextContent = '#include <fog_vertex>';
    private static partitionFragementContent = '#include <fog_fragment>';
    private static vertexCodeList: Array<{priority: number, headerCode?: string, contentCode?: string, insertPlaceBefore?: string}> = new Array();
    private static fragmentCodeList: Array<{priority: number, headerCode?: string, contentCode?: string, insertPlaceBefore?: string}> = new Array();

    public static addVertexCode(message: {priority: number, headerCode?: string, contentCode?: string, insertPlaceBefore?: string}){
        let existRepeat = MaterialShaderManager.checkRepeatCode(message, MaterialShaderManager.vertexCodeList);;
        if(existRepeat){ //有重复的shader代码片段
            return false;
        }
        MaterialShaderManager.vertexCodeList.push(message);
        return true;
    }

    public static addFragmentCode(message: {priority: number, headerCode?: string, contentCode?: string, insertPlaceBefore?: string}){
        let existRepeat = MaterialShaderManager.checkRepeatCode(message, MaterialShaderManager.fragmentCodeList);
        if(existRepeat){ //有重复的shader代码片段
            return false;
        }
        MaterialShaderManager.fragmentCodeList.push(message);
        return true;
    }

    public static getBasicVertextShaderStr(originShaderStr: string, macrosList?: Array<string>){
        MaterialShaderManager.vertexCodeList.sort((a, b) => {
            return a.priority - b.priority;
        });

        MaterialShaderManager.vertexCodeList.forEach(message => {
            originShaderStr = MaterialShaderManager.insertTextBeforePattern(originShaderStr, MaterialShaderManager.partitionHeader, message.headerCode);
            originShaderStr = MaterialShaderManager.insertTextBeforePattern(originShaderStr, MaterialShaderManager.partitionVertextContent, message.contentCode);
        });

        originShaderStr = MaterialShaderManager.insertMacros(originShaderStr, macrosList);

        return originShaderStr;
    }

    public static getBasicFragemntShaderStr(originShaderStr: string, macrosList?: Array<string>){
        MaterialShaderManager.fragmentCodeList.sort((a, b) => {
            return a.priority - b.priority;
        });

        MaterialShaderManager.fragmentCodeList.forEach(message => {
            originShaderStr = MaterialShaderManager.insertTextBeforePattern(originShaderStr, MaterialShaderManager.partitionHeader, message.headerCode);
            let insertPlaceBefore = MaterialShaderManager.partitionFragementContent;
            if(message.insertPlaceBefore){
                insertPlaceBefore = message.insertPlaceBefore;
            }
            originShaderStr = MaterialShaderManager.insertTextBeforePattern(originShaderStr, insertPlaceBefore, message.contentCode);
        });

        originShaderStr = MaterialShaderManager.insertMacros(originShaderStr, macrosList);

        return originShaderStr;
    }

    private static insertMacros(shader: string, macrosList){ //插入宏命令
        if(macrosList && macrosList.length > 0){
            macrosList.forEach(macros => {
                shader = macros + '\n' + shader;
            });
        }

        return shader;
    }

    private static checkRepeatCode(message, codeList){
        let existRepeat = false;
        for(let i=0; i<codeList.length; i++){ //检测新的代码片段和旧的代码片段是否存在重复
            let currentMessage = codeList[i];
            if(message.headerCode && currentMessage.headerCode == message.headerCode){
                existRepeat = true;
                break;
            }
            if(message.contentCode && currentMessage.contentCode == message.contentCode){
                existRepeat = true;
                break;
            }
        }

        return existRepeat;
    }

    private static insertTextBeforePattern(inputString, pattern, textToInsert) {
        if(!textToInsert){
            return inputString;
        }

        textToInsert += '\n';
        const regex = new RegExp(pattern, 'g');
        const result = inputString.replace(regex, `${textToInsert}$&`);
        return result;

    }

    private static insertTextAfterPattern(inputString, pattern, textToInsert) {
        if(!textToInsert){
            return inputString;
        }

        textToInsert += '\n';
        const regex = new RegExp(pattern, 'g');
        const result = inputString.replace(regex, `$&${textToInsert}`);
        return result;
    }
}